
if (!window.Form)
    Form = {};
(function (Form) {
	var util = window.Util,
		dom = window.Dom;
	
	/**
	 * @class Form
	 * @singleton
	 */
	
	/**
	 * 表单序列化
	 * @method serialize
	 * @param {HTMLElement|String} f 表单元素
	 * @param {String} isJson 结果类型，0(default) 为URL参数字符串；1 为JSON
	 * @return {String|JSON}
	 */
    Form.serialize = function (f, isJson) {
        f = typeof f == 'string' ? dom._(f) : f;
		var rst = !isJson ? "" : {},
			elem = "",
			qid;
        var elements = f.elements;
        var length = elements.length;
        for (var s = 0; s < length; s++) {
            elem = elements[s];
            if (elem.tagName === 'INPUT') {
                if (elem.type === 'radio' || elem.type === 'checkbox') {
                    if (!elem.checked) {
                        continue;
                    }
                }
            }
            qid = elem.name || elem.id;
            if (qid) {
				if( !isJson ){
					if (rst != "")
						rst += "&";
					rst += encodeURIComponent(qid) + "=" + encodeURIComponent(elem.value);
				}
				else
					rst[qid] = elem.value;
            }
        }
        return rst;
    }
	
	/**
	 * 设置字段的占位提示符
	 * @method setPlaceholder
	 * @param {HTMLElement|String} formId 表单元素
	 * @param {String} focusCls CSS类名
	 * @param {String} cls IE9以下，需要用图片背景解决兼容问题（文本框本身最好没有设置背景）
	 */
	Form.setPlaceholder = function(formId, focusCls, cls){
		var lgForm = _(formId), focusCls = focusCls || '',
			inps = _t(lgForm,'input'),
			isSupp= ("placeholder" in document.createElement("input"));
		if( !isSupp ){
			for(var i=0,l=inps.length;i<l;i++){
				var inp = inps[i],	ph = inp.getAttribute('placeholder');  //input元素必须有placeholder这个属性
				if( !ph || inp.type == 'password' )
					continue;
				inp.value = ph;
				addEvt(inp, 'focus', function(e){
					var elm = e.srcElement || e.target;
					if( elm.value == inp.getAttribute('placeholder') )
						elm.value = '';
					elm.className = elm.className + ' ' + focusCls;
				});
				addEvt(inp, 'blur', function(e){
					var elm = e.srcElement || e.target;
					if( !elm.value ) 
						elm.value = elm.getAttribute('placeholder');
					elm.className = elm.className.replace(new RegExp(' '+focusCls,'ig'),'');
				});
			}
		}
	};
	
	/**
	 * 表单验证器
	 * @class Form.Validator
	 * <pre><code>
<style>
.description strong { color: red; } 
</style>
调用示例:
&lt;form id="lg_form1" method="post" action="#"&gt;
&lt;div id="tip1" class="info-tips">手机号码不正确，请重新输入。&lt;/div&gt;
手机号码：&lt;input name="mobile" type="text" <strong>errTip="tip1" data-v="notNull:请输入手机号码|isMobile:手机号码不正确，请重新输入"</strong> /&gt;
服务密码：&lt;input name="pw" type="password" <strong>errTip="tip1" data-v="notNull:请输入密码" placeholder="忘记密码？可用动态密码登录"</strong> /&gt;
验证码：&lt;input name="vcode" type="text" <strong>data-v="notNull:请输入验证码"</strong> /&gt;
&lt;button id="btn_lg1"&gt;登录&lt;/button&gt;
&lt;/form&gt;

注意表单红色的配置部分，
<strong>errTip="tip1"</strong>：当该字段验证不通过时，出错信息在tip1这个元素上显示
<strong>data-v="notNull:请输入手机号码|isMobile:手机号码不正确，请重新输入"</strong> ：指定验证规则（这些规则在 {@link Form.Validator#validateMethods} 中），和出错提示方案

&lt;script type="text/javascript" src="/wap2012/js/all.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript"&gt;

var lgFormValidator = new Form.Validator({
	form: 'lg_form1', 
	triggerBtn: 'btn_lg1', 
	succCb: function(f, vRst){
		Ax.post('#', Form.serialize('lg_form1'), function(r){ alert(r); });
	}
});
&lt;/script&gt;
	 * </code></pre>
	 */
	 
	/**
	 * @cfg {HTMLElement|String} form (必须)表单元素，或者表单的ID
	 */
	/**
	 * @cfg {HTMLElement|String} triggerBtn   (必须)触发按钮
	 */
	/**
	 * @cfg {String|Object} succCb 验证成功的回调（阻止表单的提交，用于异步提交表单）{@link Form.Validator#succCb}
	 */
	/**
	 * @cfg {Object} errCb         验证失败的回调（会阻止默认的出错处理）{@link Form.Validator#errCb}
	 */
	/**
	 * @cfg {String} errCls        字段验证失败，添加的出错的样式,默认为'on'
	 */
	 
	 
	var Validator = function( option ){
	    /**
		 * 	锁定表单，禁止提交
		 * @property
		 * @type boolean
		 */
		this.LOCK = false;
		/**
		 * 开启表单验证
		 * @property
		 * @type Boolean
		 */
		this.VALIDATE_ENABLE = true;
		
		util.plainExtend(this, option);
		
		var form = this.form;
		this.form = typeof form == 'string' ? dom._(form) : form;
		if( !this.form )
			throw 'formId is not exsit!';
		
		this.setTriggerBtn( this.triggerBtn );
		
		dom.addEvt(this.form, 'submit', util.bind( this.validate, this) );
	}

	Form.Validator = Validator;
	 
    Validator.prototype = {
		/**
		 * <pre><code>
验证方法的集合,可通过{@link Form.Validator#addValidate}扩展这些验证方法集， 已包含以下验证方法：
 notNull    非空  
 isMobile   手机格式验证
		 * </code></pre>

		 * @property 
		 * @type Object
		 */
		validateMethods: {
			notNull : function (v) {
				return !!v;
			},
			isMobile : function (v) {
				return /^1(34|35|36|37|38|39|47|50|51|52|57|58|59|87|83|88|82)[0-9]{8}$/ig.test(v);
			}
		},
		
		/**
		 * 添加验证方法
		 * @method addValidate
		 * @param {string} vName
		 * @param {Function} validateFn
		 * @param {boolean} overwrite
		 * @return this
		 */
		addValidate: function( vName, validateFn, overwrite){
			if( this.validateMethods[vName] && !overwrite )
				throw 'validate '+ vName +'is exsit!';
			this.validateMethods[vName] = validateFn;
		},
		/**
		 * @method setTriggerBtn
		 * @param {string} id
		 */
		setTriggerBtn: function( id ){
			var self = this,
				form = this.form, 
				triggerBtn = this.triggerBtn;
			this.triggerBtn = typeof triggerBtn == 'string' ? dom._(triggerBtn) : triggerBtn;
			if ( this.triggerBtn ) {
				dom.addEvt( this.triggerBtn, 'click', function (e) {
					e && e.preventDefault && e.preventDefault();
					if ( !-[1, ] ) {
						form.fireEvent('onsubmit');
					} else if( self.validate() ) {
						form.submit();
					}
					return false;
				});
			}
		},
		/**
		 * @method getValidationRst
		 * @return Object 返回对每个字段的验证结果集
		 */
		getValidationRst: function () {
			
            var inps = dom._t(this.form, 'input'),  vRst = [];
            for (var i = 0, l = inps.length; i < l; i++) {
                var inp = inps[i];
                if (!/text|password|radio|checkbox/.test(inp.type))
                    continue;
                var ph = inp.getAttribute('placeholder'),
                v = inp.value == ph ? '' : inp.value;
                vData = inp.getAttribute('data-v');
                if (!vData)
                    continue;
                
                var vMethodObj = this.validateMethods;
                //提取验证数据
                vData = vData.split('|');
                for (var k = 0; k < vData.length; k++) {
                    var m = vData[k].split(':'),
                    key = m[0],
                    tip = m.length >= 1 ? m[1] : null
                        if (vMethodObj[key] && !vMethodObj[key](v)) {
                            vRst.push({
                                inp : inp,
                                tip : tip
                            });
                            break;
                        }
                }
            }
            return vRst;
        },
		/**
		 * 验证表单
		 * @method validate
		 * @return Boolean
		 */
		validate: function(e) {

			var form = this.form,
				errCls = this.errCls || 'on';
			if( !this.VALIDATE_ENABLE )
				return true;

			e && e.preventDefault && e.preventDefault();
            var vRst = this.getValidationRst();
            if (vRst.length == 0) {
                if (typeof this.succCb == 'function') {
                    if ( this.succCb(form, vRst) !== true ) {
                        return false;
                    } else
                        return true;
                } else
                    return true;
            } else {
                if (typeof this.errCb == 'function') {
                    this.errCb( this.form, vRst);
                } else {
                    for (var q = vRst.length - 1; q >= 0; q--) {
                        var obj = vRst[q],
                        inp = obj.inp,
                        errTipId = inp.getAttribute('errTip');
                        if (obj.tip && errTipId) {
							var errTipElm = dom._(errTipId);
                            if( errTipElm ) {
								errTipElm.style.display = '';
								errTipElm.innerHTML = obj.tip;
							}
						}
                        inp.className = inp.className + ' ' + errCls;
                        if (!inp.getAttribute('blurEvt')) {
                            inp.setAttribute('blurEvt', 'added');
                            dom.addEvt(inp, 'blur', function (e) {
                                var elm = e.srcElement || e.target;
                                elm.className = elm.className.replace(new RegExp('\s{0,}' + errCls, 'ig'), '');
								//var et = dom._(elm.getAttribute('errTip'));
								//if( et ) 
								//	et.style.display = 'none';
                            });
                        }
                    }
                }
                return false;
            }
        }
	}
})(Form);